package ma.platform.server.student.controller;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import jakarta.annotation.Resource;
import ma.platform.server.core.exception.CheckedException;
import ma.platform.server.core.util.BaseConvert;
import ma.platform.server.core.util.R;
import ma.platform.server.core.util.StreamUtils;
import ma.platform.server.core.context.LoginUserContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import ma.platform.server.student.dto.HomeComboDto;
import ma.platform.server.student.dto.TbDateComboDto;
import ma.platform.server.student.dto.TbStudentDto;
import ma.platform.server.student.entity.*;
import ma.platform.server.student.req.CreateResrveReq;
import ma.platform.server.student.req.QueryHistoryResrveReq;
import ma.platform.server.student.req.QueryResrveReq;
import ma.platform.server.student.service.*;
import org.apache.commons.collections.CollectionUtils;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@RestController
@RequestMapping("/wx/student")
public class WxContrller {

    @Resource
    private TbSchoolService schoolService;

    @Resource
    private TbGradeService gradeService;

    @Resource
    private TbClassesService classesService;

    @Resource
    private TbStudentService studentService;

    @Resource
    private TbComboInfoService comboInfoService;

    @Resource
    private TbDateComboService dateComboService;

    @Resource
    private TbStudentComboService tbStudentComboService;

    @Resource
    private TbStudentParentService tbStudentParentService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private TbSchoolService tbSchoolService;

    // Redis缓存key前缀
    private static final String SCHOOL_CACHE_KEY_PREFIX = "user:selected:school:";
    @Autowired
    private TbStudentService tbStudentService;


    @GetMapping("/listSchool")
    public R listSchool(@ParameterObject TbSchool tbSchool) {
        return R.ok(schoolService.list(Wrappers.<TbSchool>lambdaQuery().like(StrUtil.isNotBlank(tbSchool.getSchoolName()), TbSchool::getSchoolName, tbSchool.getSchoolName())));
    }

    @GetMapping("/listGrade")
    public R listGrade(@ParameterObject TbGrade grade) {
        return R.ok(gradeService.list(Wrappers.<TbGrade>lambdaQuery()
                .like(StrUtil.isNotBlank(grade.getGradeName()), TbGrade::getGradeName, grade.getGradeName())
                .eq(Objects.nonNull(grade.getSchoolId()), TbGrade::getSchoolId, grade.getSchoolId()).orderByAsc(TbGrade::getSortd)));
    }

    @GetMapping("/listClasses")
    public R listClasses(@ParameterObject TbClasses classes) {
        return R.ok(classesService.list(Wrappers.<TbClasses>lambdaQuery()
                .like(StrUtil.isNotBlank(classes.getClassesName()), TbClasses::getClassesName, classes.getClassesName())
                .eq(Objects.nonNull(classes.getGradeId()), TbClasses::getGradeId, classes.getGradeId())
                .eq(Objects.nonNull(classes.getSchoolId()), TbClasses::getSchoolId, classes.getSchoolId()).orderByAsc(TbClasses::getSortd)));
    }

    @GetMapping("/listStudent")
    public R listStudent(@ParameterObject TbStudent tbStudent) {
        return R.ok(studentService.list(Wrappers.<TbStudent>lambdaQuery()
                .eq(Objects.nonNull(tbStudent.getSchoolId()), TbStudent::getSchoolId, tbStudent.getSchoolId())
                .eq(Objects.nonNull(tbStudent.getGradeId()), TbStudent::getGradeId, tbStudent.getGradeId())
                .eq(Objects.nonNull(tbStudent.getClassesId()), TbStudent::getClassesId, tbStudent.getClassesId()
                ).like(StrUtil.isNotBlank(tbStudent.getName()), TbStudent::getName, tbStudent.getName())));
    }


    @GetMapping("/detail/{id}")
    public R detailStudent(@PathVariable("id") Long id) {
        TbStudent tbStudent = studentService.getById(id);
        TbStudentDto tbStudentDto = BaseConvert.convert(tbStudent, TbStudentDto.class);
        if (tbStudent != null && tbStudent.getSchoolId() != null) {
            tbStudentDto.setSchoolName(schoolService.getById(tbStudent.getSchoolId()).getSchoolName());
        }
        if (tbStudent != null && tbStudent.getGradeId() != null) {
            tbStudentDto.setGradeName(gradeService.getById(tbStudent.getGradeId()).getGradeName());
        }
        if (tbStudent != null && tbStudent.getClassesId() != null) {
            tbStudentDto.setClassesName(classesService.getById(tbStudent.getClassesId()).getClassesName());
        }
        return R.ok(tbStudentDto);
    }

    @PostMapping("/create")
    @Transactional(rollbackFor = Exception.class)
    public R createStudent(@RequestBody TbStudent tbStudent) {
        if (Objects.isNull(tbStudent.getId())) {
            return R.failed("请选择学生绑定");
        }
        tbStudentParentService.remove(Wrappers.<TbStudentParent>lambdaQuery()
                .eq(TbStudentParent::getStudentId, tbStudent.getId())
                .eq(TbStudentParent::getParentId, LoginUserContext.getUser().getId()));
        studentService.updateById(tbStudent);
        TbStudentParent studentParent = new TbStudentParent();
        studentParent.setStudentId(tbStudent.getId());
        studentParent.setParentId(LoginUserContext.getUser().getId());
        tbStudentParentService.save(studentParent);
        return R.ok();

//        TbStudent baseData = studentService.getOne(Wrappers.<TbStudent>lambdaQuery()
//                .eq(TbStudent::getSchoolId, tbStudent.getSchoolId()).eq(TbStudent::getGradeId, tbStudent.getGradeId())
//                .eq(TbStudent::getClassesId, tbStudent.getClassesId()).eq(TbStudent::getName, tbStudent.getName()).last("limit 1"));
//        if (Objects.nonNull(baseData)) {
//            baseData.setParentId(tbStudent.getParentId());
//            tbStudent.setId(baseData.getId());
//            studentService.updateById(baseData);
//        } else {
//            studentService.save(tbStudent);
//        }
//        TbStudentParent studentParent = new TbStudentParent();
//        studentParent.setStudentId(tbStudent.getId());
//        studentParent.setParentId(tbStudent.getParentId());
//        tbStudentParentService.save(studentParent);
//        return R.ok();
    }


    @PostMapping("/removeBind/{id}")
    @Transactional(rollbackFor = Exception.class)
    public R removeBindStudent(@PathVariable("id") Long id) {
        studentService.removeBind(id);
        tbStudentParentService.remove(Wrappers.<TbStudentParent>lambdaQuery().eq(TbStudentParent::getStudentId, id));
        return R.ok();
    }

    @PostMapping("/update")
    public R updateStudent(@RequestBody TbStudent tbStudent) {
        studentService.updateById(tbStudent);
        return R.ok();
    }

    @GetMapping("/bindList/{id}")
    public R bindStudentList(@PathVariable("id") Long id) {
        List<TbStudent> studentList = studentService.listStudent(LoginUserContext.getUser().getId());
        if (CollectionUtils.isEmpty(studentList)) {
            return R.ok(studentList);
        }
        Map<Long, String> schoolMap = Maps.newHashMap();
        Map<Long, String> gradeMap = Maps.newHashMap();
        Map<Long, String> classesMap = Maps.newHashMap();
        List<Long> schoolIdList = StreamUtils.convert2List(studentList, TbStudent::getSchoolId);
        if (CollectionUtils.isNotEmpty(schoolIdList)) {
            List<TbSchool> schoolList = schoolService.listByIds(schoolIdList);
            schoolMap = StreamUtils.getMap(schoolList, TbSchool::getId, TbSchool::getSchoolName);
        }

        List<Long> gradeIdList = StreamUtils.convert2List(studentList, TbStudent::getGradeId);
        if (CollectionUtils.isNotEmpty(gradeIdList)) {
            List<TbGrade> schoolList = gradeService.listByIds(gradeIdList);
            gradeMap = StreamUtils.getMap(schoolList, TbGrade::getId, TbGrade::getGradeName);
        }

        List<Long> classesIdList = StreamUtils.convert2List(studentList, TbStudent::getClassesId);
        if (CollectionUtils.isNotEmpty(classesIdList)) {
            List<TbClasses> schoolList = classesService.listByIds(classesIdList);
            classesMap = StreamUtils.getMap(schoolList, TbClasses::getId, TbClasses::getClassesName);
        }

        List<TbStudentDto> tbStudentDtos = BaseConvert.convertList(studentList, TbStudentDto.class);
        for (TbStudentDto tbStudentDto : tbStudentDtos) {
            tbStudentDto.setSchoolName(schoolMap.get(tbStudentDto.getSchoolId()));
            tbStudentDto.setGradeName(gradeMap.get(tbStudentDto.getGradeId()));
            tbStudentDto.setClassesName(classesMap.get(tbStudentDto.getClassesId()));
        }
        return R.ok(tbStudentDtos);
    }

    @GetMapping("/homeCombo")
    public R getHomeCombo(@RequestParam(required = false) Long schoolId) {
        Long userId = LoginUserContext.getUser().getId();
        if (Objects.isNull(schoolId)){
            schoolId = 223L;
        }
        DateTime startTime = DateUtil.beginOfWeek(new Date());
        DateTime endTime = DateUtil.endOfWeek(new Date());
        List<HomeComboDto> comboDtoList = getHomeComboDtos(startTime, endTime, schoolId);

        // 在返回结果中包含当前选择的学校ID，方便前端缓存
        Map<String, Object> result = Maps.newHashMap();
        result.put("selectedSchoolId", schoolId);
        result.put("comboList", comboDtoList);

        return R.ok(result);
    }


    @GetMapping("/selectCombo")
    public R getSelectCombo(@RequestParam(required = false) Long schoolId) {
        Long userId = LoginUserContext.getUser().getId();
        Long selectSchoolId = schoolId;
        if (Objects.isNull(selectSchoolId)){
            selectSchoolId = 223L;
        }

        // 获取当前时间
        Date now = new Date();
        DateTime nextWeekStartTime;
        DateTime nextWeekEndTime;

        // 判断当前是否是周五18:30之后、周六或周日
        int dayOfWeek = DateUtil.dayOfWeek(now);
        boolean isFridayAfter1830 = dayOfWeek == 6  // 周五是6
                && now.getTime() > DateUtil.parse(DateUtil.formatDate(now) + " 18:30:00").getTime();
        boolean isWeekend = dayOfWeek == 7 || dayOfWeek == 1;  // 周六是7，周日是1

        if (isFridayAfter1830 || isWeekend) {
            // 如果是周五18:30后、周六或周日，显示下下周的时间
            nextWeekStartTime = DateUtil.beginOfWeek(DateUtil.offsetDay(now, 14));
            nextWeekEndTime = DateUtil.endOfWeek(DateUtil.offsetDay(now, 14));
        } else {
            // 否则显示下周的时间
            nextWeekStartTime = DateUtil.beginOfWeek(DateUtil.offsetDay(now, 7));
            nextWeekEndTime = DateUtil.endOfWeek(DateUtil.offsetDay(now, 7));
        }

        List<HomeComboDto> comboDtoList = getHomeComboDtos(nextWeekStartTime, nextWeekEndTime, selectSchoolId);
        if (Objects.isNull(schoolId)){
            return R.ok(comboDtoList);
        }
        // 在返回结果中包含当前选择的学校ID，方便前端缓存
        Map<String, Object> result = Maps.newHashMap();
        result.put("selectedSchoolId", selectSchoolId);
        result.put("comboList", comboDtoList);

        return R.ok(result);
    }

    /**
     * 根据学生ID获取学生所在学校的菜单列表
     * @param studentId 学生ID
     * @return 菜单列表
     */
    @GetMapping("/selectComboByStudent")
    public R getSelectComboByStudent(@RequestParam Long studentId) {
        // 根据学生ID获取学生信息
        TbStudentParent studentParent = tbStudentParentService.getOne(
            Wrappers.<TbStudentParent>lambdaQuery()
                .eq(TbStudentParent::getStudentId, studentId)
                .eq(TbStudentParent::getParentId, LoginUserContext.getUser().getId())
        );

        if (studentParent == null) {
            throw new CheckedException("学生信息不存在或无权限访问");
        }

        // 获取学生所在的学校ID
        TbStudent tbStudent = studentService.getById(studentId);
        Long schoolId = tbStudent.getSchoolId();

        // 缓存用户选择的学校（基于学生的学校）
        cacheUserSelectedSchool(LoginUserContext.getUser().getId(), schoolId);

        // 获取当前时间
        Date now = new Date();
        DateTime nextWeekStartTime;
        DateTime nextWeekEndTime;

        // 判断当前是否是周五18:30之后、周六或周日
        int dayOfWeek = DateUtil.dayOfWeek(now);
        boolean isFridayAfter1830 = dayOfWeek == 6  // 周五是6
                && now.getTime() > DateUtil.parse(DateUtil.formatDate(now) + " 18:30:00").getTime();
        boolean isWeekend = dayOfWeek == 7 || dayOfWeek == 1;  // 周六是7，周日是1

        if (isFridayAfter1830 || isWeekend) {
            // 如果是周五18:30后、周六或周日，显示下下周的时间
            nextWeekStartTime = DateUtil.beginOfWeek(DateUtil.offsetDay(now, 14));
            nextWeekEndTime = DateUtil.endOfWeek(DateUtil.offsetDay(now, 14));
        } else {
            // 否则显示下周的时间
            nextWeekStartTime = DateUtil.beginOfWeek(DateUtil.offsetDay(now, 7));
            nextWeekEndTime = DateUtil.endOfWeek(DateUtil.offsetDay(now, 7));
        }

        List<HomeComboDto> comboDtoList = getHomeComboDtos(nextWeekStartTime, nextWeekEndTime, schoolId);

        // 在返回结果中包含学生信息和学校ID
        Map<String, Object> result = Maps.newHashMap();
        result.put("studentId", studentId);
        result.put("schoolId", schoolId);
        result.put("comboList", comboDtoList);

        return R.ok(result);
    }

    /**
     * 缓存用户选择的学校
     * @param userId 用户ID
     * @param schoolId 学校ID
     */
    private void cacheUserSelectedSchool(Long userId, Long schoolId) {
        String cacheKey = SCHOOL_CACHE_KEY_PREFIX + userId;
        // 缓存30天
        redisTemplate.opsForValue().set(cacheKey, schoolId, 30, java.util.concurrent.TimeUnit.DAYS);
    }

    /**
     * 获取用户缓存的学校ID
     * @param userId 用户ID
     * @return 学校ID，如果没有缓存则返回null
     */
    private Long getCachedUserSelectedSchool(Long userId) {
        String cacheKey = SCHOOL_CACHE_KEY_PREFIX + userId;
        Object cachedSchoolId = redisTemplate.opsForValue().get(cacheKey);
        return cachedSchoolId != null ? Long.valueOf(cachedSchoolId.toString()) : null;
    }

    /**
     * 获取默认学校ID（第一个学校）
     * @return 默认学校ID，如果没有学校则返回null
     */
    private Long getDefaultSchoolId() {
        List<TbSchool> schoolList = tbSchoolService.list(
            Wrappers.<TbSchool>lambdaQuery()
                .orderByAsc(TbSchool::getId)
                .last("LIMIT 1")
        );
        return schoolList.isEmpty() ? null : schoolList.get(0).getId();
    }

    /**
     * 添加设置用户选择学校的接口
     * @param schoolId 学校ID
     * @return 操作结果
     */
    @PostMapping("/setSelectedSchool")
    public R setSelectedSchool(@RequestParam Long schoolId) {
        Long userId = LoginUserContext.getUser().getId();

        // 验证学校是否存在
        TbSchool school = tbSchoolService.getById(schoolId);
        if (school == null) {
            throw new CheckedException("学校不存在");
        }

        // 缓存用户选择的学校
        cacheUserSelectedSchool(userId, schoolId);

        return R.ok("学校设置成功");
    }

    /**
     * 获取用户当前选择的学校
     * @return 当前选择的学校信息
     */
    @GetMapping("/getSelectedSchool")
    public R getSelectedSchool() {
        Long userId = LoginUserContext.getUser().getId();
        Long schoolId = getCachedUserSelectedSchool(userId);

        if (schoolId == null) {
            schoolId = getDefaultSchoolId();
            if (schoolId != null) {
                cacheUserSelectedSchool(userId, schoolId);
            }
        }

        if (schoolId == null) {
            return R.ok(null);
        }

        TbSchool school = tbSchoolService.getById(schoolId);
        return R.ok(school);
    }

    @GetMapping("/selectComboByDate")
    public R selectComboByDate(@RequestParam("date") String date, @RequestParam(required = false) Long studentId) {
        TbStudent student = tbStudentService.getById(studentId);

        //获取指定日期的套餐
        DateTime dateTime = DateUtil.parse(date, "yyyy-MM-dd");

        // 查询学生在该日期的预约记录
        TbStudentCombo studentCombo = tbStudentComboService.getOne(
                Wrappers.<TbStudentCombo>lambdaQuery()
                        .eq(TbStudentCombo::getStudentId, studentId)
                        .eq(TbStudentCombo::getDate, dateTime)
        );
        if (Objects.isNull(studentCombo)){
            List<HomeComboDto> homeComboDtos = getHomeComboDtos(dateTime, dateTime, student.getSchoolId());
            if (CollectionUtils.isEmpty(homeComboDtos)) {
                return R.ok();
            }
            Map<String, Object> result = Maps.newHashMap();
            result.put("comboList", homeComboDtos.get(0).getComboList());
            return R.ok(result);
        }
        Long dateComboId = studentCombo.getDateComboId();
        TbDateCombo tbDateCombo = dateComboService.getById(dateComboId);


        List<HomeComboDto> homeComboDtos = getHomeComboDtos(dateTime, dateTime, tbDateCombo.getSchoolId());
        if (CollectionUtils.isEmpty(homeComboDtos)) {
            return R.ok();
        }


        // 在返回结果中包含当前选择的学校ID和学生选择的套餐信息
        Map<String, Object> result = Maps.newHashMap();
        result.put("comboList", homeComboDtos.get(0).getComboList());
        // 如果学生有预约记录，返回选择的套餐ID
        if (studentCombo != null) {
            result.put("selectedComboId", studentCombo.getDateComboId());
        } else {
            result.put("selectedComboId", null);
        }

        return R.ok(result);
    }


    private List<HomeComboDto> getHomeComboDtos(DateTime startTime, DateTime endTime, Long schoolId) {
        List<TbDateCombo> tbDateComboList = dateComboService.list(Wrappers.<TbDateCombo>lambdaQuery()
                .eq(Objects.nonNull(schoolId), TbDateCombo::getSchoolId, schoolId).
                between(TbDateCombo::getDate, startTime, endTime).orderByAsc(TbDateCombo::getDate));
        List<TbDateComboDto> dtoList = BaseConvert.convertList(tbDateComboList, TbDateComboDto.class);

        List<Long> comboIdList = StreamUtils.convert2List(dtoList, TbDateComboDto::getComboId);
        if (CollectionUtils.isNotEmpty(comboIdList)) {
            List<TbComboInfo> tbComboInfos = comboInfoService.listByIds(comboIdList);
            Map<Long, String> comboMap = StreamUtils.getMap(tbComboInfos, TbComboInfo::getId, TbComboInfo::getName);
            dtoList.forEach(item -> item.setComboName(comboMap.get(item.getComboId())));
        }

        List<String> weekList = Lists.newArrayList("", "周日", "周一", "周二", "周三", "周四", "周五", "周六");
        List<String> sortWeekList = Lists.newArrayList("周一", "周二", "周三", "周四", "周五", "周六", "周日");
        Map<String, List<TbDateComboDto>> groupMap = Maps.newHashMap();
        for (TbDateComboDto item : dtoList) {
            String weekDay = weekList.get(DateUtil.dayOfWeek(item.getDate()));
            if (!groupMap.containsKey(weekDay)) {
                groupMap.put(weekDay, Lists.newArrayList());
            }
            groupMap.get(weekDay).add(item);
        }
        List<HomeComboDto> comboDtoList = Lists.newArrayList();
        for (String weekDay : sortWeekList) {
            List<TbDateComboDto> weekDataList = groupMap.get(weekDay);
            if (CollectionUtils.isNotEmpty(weekDataList)) {
                HomeComboDto homeComboDto = new HomeComboDto();
                homeComboDto.setWeek(weekDay);
                homeComboDto.setDate(DateUtil.formatDate(weekDataList.get(0).getDate()));
                homeComboDto.setComboList(weekDataList);
                comboDtoList.add(homeComboDto);
            }

        }
        return comboDtoList;
    }

    @GetMapping("/combo/{id}")
    public R detailCombo(@PathVariable("id") Long id) {
        TbDateCombo tbDateCombo = dateComboService.getById(id);
        TbDateComboDto tbDateComboDto = BaseConvert.convert(tbDateCombo, TbDateComboDto.class);
        if (Objects.isNull(tbDateComboDto)) {
            throw new CheckedException("套餐不存在");
        }
        TbComboInfo comboInfo = comboInfoService.getById(tbDateComboDto.getComboId());
        tbDateComboDto.setComboName(comboInfo.getName());
        return R.ok(tbDateComboDto);
    }

    @PostMapping("/createResrve")
    public R createResrve(@RequestBody CreateResrveReq req) {
        tbStudentComboService.createResrve(req);
        return R.ok();
    }

    @PostMapping("/listResrve")
    public R listResrve(@RequestBody QueryResrveReq req) {
        List<TbStudentCombo> dataList = tbStudentComboService.list(Wrappers.<TbStudentCombo>lambdaQuery().eq(TbStudentCombo::getStudentId, req.getStudentId()).in(TbStudentCombo::getDate, req.getDateList()));
        return R.ok(dataList);
    }

    @GetMapping("/listHistoryResrve")
    public R listHistoryResrve(@ParameterObject QueryHistoryResrveReq req) {
        List<TbDateComboDto> dataList = tbStudentComboService.listHistoryResrve(req);
        return R.ok(dataList);
    }
}
